package com.zhouqinuan.spring.cloud.develop.framework.fastdfs.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.csource.fastdfs.UploadCallback;
import org.springframework.web.multipart.MultipartFile;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FastDFSService {

    private TrackerClient trackerClient;

    private String uploadHost;

	public TrackerClient getTrackerClient() {
		return trackerClient;
	}

	public void setTrackerClient(TrackerClient trackerClient) {
		this.trackerClient = trackerClient;
	}

    public String getUploadHost() {
		return uploadHost;
	}

	public void setUploadHost(String uploadHost) {
		this.uploadHost = uploadHost;
	}

	/**
	 * 通过本地文件上传 
	 */
	public String upload(String localFilename) throws Exception {
		TrackerServer trackerServer = null;
		StorageServer storageServer = null;
		try {
			trackerServer = trackerClient.getConnection();
			storageServer = trackerClient.getStoreStorage(trackerServer);
			StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);
			NameValuePair[] meta_list = null; // new NameValuePair[0];
			String file_ext_name = localFilename.substring(localFilename.lastIndexOf(".") + 1);

			return uploadHost + storageClient1.upload_file1(localFilename, file_ext_name, meta_list);

		} finally {
			if (null != storageServer) {
				storageServer.close();
			}

			if (null != trackerServer) {
				trackerServer.close();
			}
		}
	}

	/**
	 * 下载文件 
	 */
	public byte[] download(String group, String filePath) throws Exception {
		TrackerServer trackerServer = null;
		StorageServer storageServer = null;
		try {
			trackerServer = trackerClient.getConnection();
			storageServer = trackerClient.getStoreStorage(trackerServer);
			StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);

			return storageClient1.download_file(group, filePath);

		} finally {
			if (null != storageServer) {
				storageServer.close();
			}

			if (null != trackerServer) {
				trackerServer.close();
			}
		}
	}

	/**
	 * 删除对应链接的文件 
	 */
	public int delete(String fileUrl) throws Exception {
		TrackerServer trackerServer = null;
		StorageServer storageServer = null;
		try {
			String fileId = fileUrl.replaceFirst(uploadHost, "");
			trackerServer = trackerClient.getConnection();
			storageServer = trackerClient.getStoreStorage(trackerServer);
			StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);

			log.info("delete_file1 is file_id: {}", fileId);

			return storageClient1.delete_file1(fileId);

		} finally {
			if (null != storageServer) {
				storageServer.close();
			}
			if (null != trackerServer) {
				trackerServer.close();
			}
		}
	}

	/**
	 * 通过本地数据上传
	 */
	public String upload(byte[] data, String fileExtName) throws Exception {
		TrackerServer trackerServer = null;
		StorageServer storageServer = null;
		try {
			trackerServer = trackerClient.getConnection();
			storageServer = trackerClient.getStoreStorage(trackerServer);
			StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);

			return uploadHost + storageClient1.upload_file1(data, fileExtName, null);

		} finally {
			if (null != storageServer) {
				storageServer.close();
			}

			if (null != trackerServer) {
				trackerServer.close();
			}
		}
	}

    /**
     * 将一个网络上的图片地址里的图片上传到文件服务器并返回上传后的地址
     */
	public String uploadPathWithExtension(String imgPath, String extension) throws Exception {

		URL url = new URL(imgPath);
		URLConnection conn = url.openConnection();
		InputStream inputStream = conn.getInputStream();
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

		try {
			int len = 0;
			byte[] buf = new byte[1024];
			// 将压缩包内符合要求的文件写入字节数组输出流中
			while ((len = inputStream.read(buf, 0, 1024)) != -1) {
				outputStream.write(buf, 0, len);
			}
			byte[] data = outputStream.toByteArray();
			return upload(data, extension);
		} finally {
			if (outputStream != null) {
				outputStream.close();
			}
			if (inputStream != null) {
				inputStream.close();
			}
		}
	}

    /**
     * 支持上传大文件，使用流边读边上传
     *
     */
	public String upload(MultipartFile multipartFile) throws Exception {
		TrackerServer trackerServer = null;
		StorageServer storageServer = null;

		try {
			InputStream inputStream = multipartFile.getInputStream();
			String fileName = multipartFile.getOriginalFilename();
			String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
			int fileLength = inputStream.available(); // 获取文件大小

			NameValuePair[] metaList = new NameValuePair[3];
			metaList[0] = new NameValuePair("fileName", fileName);
			metaList[1] = new NameValuePair("fileExtName", extension);
			metaList[2] = new NameValuePair("fileLength", String.valueOf(fileLength));
			UploadFileCallback uploadFileCallback = new UploadFileCallback(inputStream);

			trackerServer = trackerClient.getConnection();
			storageServer = trackerClient.getStoreStorage(trackerServer);
			StorageClient1 storageClient1 = new StorageClient1(trackerServer, storageServer);			
			String[] parts = storageClient1.upload_file(null, fileLength, uploadFileCallback, extension, metaList);
			String path = parts != null ? parts[0] + "/" + parts[1] : null;

			return uploadHost + path;

		} finally {
			if (null != storageServer) {
				storageServer.close();
			}

			if (null != trackerServer) {
				trackerServer.close();
			}
		}
	}
	
    /**
     * 上传文件回调
     */
	public static class UploadFileCallback implements UploadCallback {

		private InputStream inputStream;

		public UploadFileCallback(InputStream inputStream) {
			this.inputStream = inputStream;
		}

		@Override
		public int send(OutputStream outputStream) throws IOException {

			byte[] bs = new byte[1024];
			int i = 0;

			try {
				while ((i = inputStream.read(bs)) != -1) {
					outputStream.write(bs, 0, i);
				}
				outputStream.flush();
			} catch (Exception e) {
				log.error("上传文件回调失败：{}", e);
			}

			return 0;
		}
	}
}
